home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1989, 1992, 1993, 1994 Aladdin Enterprises. All rights reserved.
-
- This file is part of Aladdin Ghostscript.
-
- Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
- or distributor accepts any responsibility for the consequences of using it,
- or for whether it serves any particular purpose or works at all, unless he
- or she says so in writing. Refer to the Aladdin Ghostscript Free Public
- License (the "License") for full details.
-
- Every copy of Aladdin Ghostscript must include a copy of the License,
- normally in a plain ASCII text file named PUBLIC. The License grants you
- the right to copy, modify and redistribute Aladdin Ghostscript, but only
- under certain conditions described in the License. Among other things, the
- License requires that the copyright notice and this notice be preserved on
- all copies.
- */
-
- /* iscanbin.c */
- /* Ghostscript binary token scanner */
- #include "math_.h"
- #include "memory_.h"
- #include "ghost.h"
- #include "gsutil.h"
- #include "stream.h"
- #include "strimpl.h" /* for sfilter.h */
- #include "sfilter.h" /* for iscan.h */
- #include "errors.h"
- #include "ialloc.h"
- #include "idict.h"
- #include "dstack.h" /* for immediately evaluated names */
- #include "ostack.h" /* must precede iscan.h */
- #include "iname.h"
- #include "iscan.h" /* for scan_Refill */
- #include "iutil.h"
- #include "ivmspace.h"
- #include "store.h"
- #include "bseq.h"
- #include "btoken.h"
- #include "ibnum.h"
-
- /* Define the number of required initial bytes for binary tokens. */
- const byte bin_token_bytes[] = { bin_token_bytes_values };
-
- /* Import the system and user name tables */
- extern ref system_names, user_names;
-
- /* Forward references */
- private int scan_bin_num_array_continue(P3(stream *, ref *, scanner_state *));
- private int scan_bin_string_continue(P3(stream *, ref *, scanner_state *));
- private int scan_bos_continue(P3(stream *, ref *, scanner_state *));
- private byte *scan_bos_resize(P3(scanner_state *, uint, uint));
- private int scan_bos_string_continue(P3(stream *, ref *, scanner_state *));
-
- /* Scan a binary token. Called from the main scanner */
- /* when it encounters an ASCII code 128-159, */
- /* if binary tokens are being recognized (object format != 0). */
- #define pbs (&pstate->s_ss.binary)
- int
- scan_binary_token(stream *s, ref *pref, scanner_state *pstate)
- { s_declare_inline(s, p, rlimit);
- #define return_skip(n) { p += n; s_end_inline(s, p, rlimit); return 0; }
- int num_format, code;
- uint arg;
- uint wanted;
- uint rcnt;
- s_begin_inline(s, p, rlimit);
- wanted = binary_token_bytes(*p) - 1;
- rcnt = rlimit - p;
- #define return_refill()\
- { sputback_inline(s, p, rlimit); s_end_inline(s, p, rlimit);\
- pstate->s_scan_type = scanning_none; return scan_Refill;\
- }
- if ( rcnt < wanted )
- return_refill();
- switch ( *p )
- {
- case bt_seq_IEEE_msb:
- num_format = num_msb + num_float_IEEE; goto bseq;
- case bt_seq_IEEE_lsb:
- num_format = num_lsb + num_float_IEEE; goto bseq;
- case bt_seq_native_msb:
- num_format = num_msb + num_float_native; goto bseq;
- case bt_seq_native_lsb:
- num_format = num_lsb + num_float_native;
- bseq: pbs->num_format = num_format;
- { uint top_size = p[1];
- uint hsize, size;
- if ( top_size == 0 )
- { /* Extended header (2-byte array size, */
- /* 4-byte length) */
- ulong lsize;
- if ( rcnt < 7 )
- return_refill();
- top_size = sdecodeshort(p + 2, num_format);
- lsize = sdecodelong(p + 4, num_format);
- if ( (size = lsize) != lsize )
- return_error(e_limitcheck);
- hsize = 8;
- }
- else
- { /* Normal header (1-byte array size, 2-byte length). */
- /* We already checked rcnt >= 3. */
- size = sdecodeshort(p + 2, num_format);
- hsize = 4;
- }
- if ( size < hsize )
- return_error(e_syntaxerror);
- /* Preallocate an array large enough for the worst case, */
- /* namely, all objects and no strings. */
- code = ialloc_ref_array(&pbs->bin_array,
- a_all + a_executable,
- size / sizeof(ref),
- "binary object sequence(objects)");
- if ( code < 0 )
- return code;
- p += hsize - 1;
- size -= hsize;
- s_end_inline(s, p, rlimit);
- pbs->max_array_index = pbs->top_size = top_size;
- pbs->min_string_index = pbs->size = size;
- pbs->index = 0;
- }
- pstate->s_da.is_dynamic = false;
- pstate->s_da.base = pstate->s_da.next =
- pstate->s_da.limit = pstate->s_da.buf;
- code = scan_bos_continue(s, pref, pstate);
- if ( code == scan_Refill || code < 0 )
- { /* Clean up array for GC. */
- uint index = pbs->index;
- refset_null(pbs->bin_array.value.refs + index,
- r_size(&pbs->bin_array) - index);
- pbs->cont = scan_bos_continue;
- }
- return code;
- case bt_int32_msb:
- num_format = num_msb + num_int32; goto num;
- case bt_int32_lsb:
- num_format = num_lsb + num_int32; goto num;
- case bt_int16_msb:
- num_format = num_msb + num_int16; goto num;
- case bt_int16_lsb:
- num_format = num_lsb + num_int16; goto num;
- case bt_int8:
- make_int(pref, (p[1] ^ 128) - 128);
- return_skip(1);
- case bt_fixed:
- num_format = p[1];
- if ( !num_is_valid(num_format) )
- return_error(e_syntaxerror);
- wanted = 1 + encoded_number_bytes(num_format);
- if ( rcnt < wanted )
- return_refill();
- code = sdecode_number(p + 2, num_format, pref);
- goto rnum;
- case bt_float_IEEE_msb:
- num_format = num_msb + num_float_IEEE; goto num;
- case bt_float_IEEE_lsb:
- num_format = num_lsb + num_float_IEEE; goto num;
- case bt_float_native:
- num_format = num_float_native;
- num: code = sdecode_number(p + 1, num_format, pref);
- rnum: switch ( code )
- {
- case t_integer: case t_real:
- r_set_type(pref, code);
- break;
- case t_null:
- return_error(e_syntaxerror);
- default:
- return code;
- }
- return_skip(wanted);
- case bt_boolean:
- arg = p[1];
- if ( arg & ~1 )
- return_error(e_syntaxerror);
- make_bool(pref, arg);
- return_skip(1);
- case bt_string_256:
- arg = p[1]; p++; goto str;
- case bt_string_64k_msb:
- arg = (p[1] << 8) + p[2]; p += 2; goto str;
- case bt_string_64k_lsb:
- arg = p[1] + (p[2] << 8); p += 2; goto str;
- str: { byte *str = ialloc_string(arg, "string token");
- if ( str == 0 )
- return_error(e_VMerror);
- s_end_inline(s, p, rlimit);
- pstate->s_da.base = pstate->s_da.next = str;
- pstate->s_da.limit = str + arg;
- code = scan_bin_string_continue(s, pref, pstate);
- if ( code == scan_Refill || code < 0 )
- { pstate->s_da.is_dynamic = true;
- make_null(&pbs->bin_array); /* clean up for GC */
- pbs->cont = scan_bin_string_continue;
- }
- return code;
- }
- case bt_litname_system:
- code = array_get(&system_names, p[1], pref);
- goto lname;
- case bt_execname_system:
- code = array_get(&system_names, p[1], pref);
- goto xname;
- case bt_litname_user:
- code = array_get(&user_names, p[1], pref);
- lname: if ( code < 0 ) return code;
- if ( !r_has_type(pref, t_name) )
- return_error(e_undefined);
- return_skip(1);
- case bt_execname_user:
- code = array_get(&user_names, p[1], pref);
- xname: if ( code < 0 ) return code;
- if ( !r_has_type(pref, t_name) )
- return_error(e_undefined);
- r_set_attrs(pref, a_executable);
- return_skip(1);
- case bt_num_array:
- num_format = p[1];
- if ( !num_is_valid(num_format) )
- return_error(e_syntaxerror);
- arg = sdecodeshort(p + 2, num_format);
- code = ialloc_ref_array(&pbs->bin_array, a_all, arg,
- "number array token");
- if ( code < 0 )
- return code;
- pbs->num_format = num_format;
- pbs->index = 0;
- p += 3;
- s_end_inline(s, p, rlimit);
- code = scan_bin_num_array_continue(s, pref, pstate);
- if ( code == scan_Refill || code < 0 )
- { /* Make sure the array is clean for the GC. */
- refset_null(pbs->bin_array.value.refs + pbs->index,
- arg - pbs->index);
- pbs->cont = scan_bin_num_array_continue;
- }
- return code;
- }
- return_error(e_syntaxerror);
- }
-
- /* Continue collecting a binary string. */
- private int
- scan_bin_string_continue(stream *s, ref *pref, scanner_state *pstate)
- { byte *q = pstate->s_da.next;
- uint wanted = pstate->s_da.limit - q;
- uint rcnt;
- sgets(s, q, wanted, &rcnt);
- if ( rcnt == wanted )
- { /* Finished collecting the string. */
- make_string(pref, a_all | icurrent_space,
- pstate->s_da.limit - pstate->s_da.base,
- pstate->s_da.base);
- return 0;
- }
- pstate->s_da.next = q + rcnt;
- pstate->s_scan_type = scanning_binary;
- return scan_Refill;
- }
-
- /* Continue scanning a binary number array. */
- private int
- scan_bin_num_array_continue(stream *s, ref *pref, scanner_state *pstate)
- { uint index = pbs->index;
- ref *np = pbs->bin_array.value.refs + index;
- uint wanted = encoded_number_bytes(pbs->num_format);
- for ( ; index < r_size(&pbs->bin_array); index++, np++ )
- { int code;
- if ( sbufavailable(s) < wanted )
- { pbs->index = index;
- pstate->s_scan_type = scanning_binary;
- return scan_Refill;
- }
- code = sdecode_number(sbufptr(s), pbs->num_format, np);
- switch ( code )
- {
- case t_integer: case t_real:
- r_set_type(np, code);
- sbufskip(s, wanted);
- break;
- case t_null:
- return_error(e_syntaxerror);
- default:
- return code;
- }
- }
- *pref = pbs->bin_array;
- return 0;
- }
-
- /*
- * Continue scanning a binary object sequence. We preallocated space for
- * the largest possible number of objects, but not for strings, since
- * the latter would probably be a gross over-estimate. Instead,
- * we wait until we see the first string or name, and allocate string space
- * based on the hope that its string index is the smallest one we will see.
- * If this turns out to be wrong, we may have to reallocate, and adjust
- * all the pointers.
- */
- #define sizeof_bin_seq_obj ((uint)sizeof(bin_seq_obj))
- private int
- scan_bos_continue(register stream *s, ref *pref, scanner_state *pstate)
- { s_declare_inline(s, p, rlimit);
- uint max_array_index = pbs->max_array_index;
- uint min_string_index = pbs->min_string_index;
- int format = pbs->num_format;
- #if arch_is_big_endian
- # define must_swap_bytes num_is_lsb(format)
- #else
- # define must_swap_bytes !num_is_lsb(format)
- #endif
- uint index = pbs->index;
- uint size = pbs->size;
- ref *abase = pbs->bin_array.value.refs;
- int code;
- s_begin_inline(s, p, rlimit);
- for ( ; index < max_array_index; index++ )
- { bin_seq_obj ob;
- byte bt;
- ref *op = abase + index;
- uint atype, sattrs;
- s_end_inline(s, p, rlimit); /* in case of error */
- if ( rlimit - p < sizeof_bin_seq_obj )
- { pbs->index = index;
- pbs->max_array_index = max_array_index;
- pbs->min_string_index = min_string_index;
- pstate->s_scan_type = scanning_binary;
- return scan_Refill;
- }
- memcpy(&ob, p + 1, sizeof_bin_seq_obj);
- p += sizeof_bin_seq_obj;
- #define do_swap_size()\
- bt = ob.size.b[0], ob.size.b[0] = ob.size.b[1], ob.size.b[1] = bt
- #define swap_size()\
- if ( must_swap_bytes ) do_swap_size()
- #define do_swap_value()\
- bt = ob.value.b[0], ob.value.b[0] = ob.value.b[3], ob.value.b[3] = bt,\
- bt = ob.value.b[1], ob.value.b[1] = ob.value.b[2], ob.value.b[2] = bt
- #define swap_value()\
- if ( must_swap_bytes ) do_swap_value()
- #define swap_size_also_value()\
- if ( must_swap_bytes ) do_swap_size(), do_swap_value()
- switch ( ob.tx & 0x7f )
- {
- case bs_null:
- make_null(op); break;
- case bs_integer:
- swap_value();
- make_int(op, ob.value.w);
- break;
- case bs_real:
- if ( ob.size.w != 0 ) /* fixed-point number */
- { swap_size_also_value();
- ob.value.f = (float)ldexp((float)ob.value.w,
- -ob.size.w);
- }
- else if ( (format & ~(num_lsb | num_msb)) !=
- num_float_native
- )
- { ob.value.f = sdecodefloat(ob.value.b, format);
- }
- make_real(op, ob.value.f);
- break;
- case bs_boolean:
- swap_value();
- make_bool(op, (ob.value.w == 0 ? 0 : 1));
- break;
- case bs_string:
- swap_size_also_value();
- sattrs = (ob.tx < 128 ? a_all : a_all + a_executable);
- str: if ( ob.size.w == 0 )
- { /* For zero-length strings, the offset */
- /* doesn't matter, and may be zero. */
- make_empty_string(op, sattrs);
- break;
- }
- if ( ob.value.w < max_array_index * sizeof_bin_seq_obj ||
- ob.value.w + ob.size.w > size
- )
- return_error(e_syntaxerror);
- if ( ob.value.w < min_string_index )
- { /* We have to (re)allocate the strings. */
- uint str_size = size - ob.value.w;
- byte *sbase;
- if ( pstate->s_da.is_dynamic )
- sbase = scan_bos_resize(pstate, str_size,
- index);
- else
- sbase = ialloc_string(str_size,
- "bos strings");
- if ( sbase == 0 )
- return_error(e_VMerror);
- pstate->s_da.is_dynamic = true;
- pstate->s_da.base = pstate->s_da.next = sbase;
- pstate->s_da.limit = sbase + str_size;
- min_string_index = ob.value.w;
- }
- make_string(op, sattrs | icurrent_space, ob.size.w,
- pstate->s_da.base +
- (ob.value.w - min_string_index));
- break;
- case bs_name:
- sattrs = (ob.tx < 128 ? 0 : a_executable);
- goto nam;
- case bs_eval_name:
- sattrs = a_readonly;
- nam: swap_size_also_value();
- switch ( ob.size.w )
- {
- case 0:
- code = array_get(&user_names, ob.value.w, op);
- goto usn;
- case 0xffff:
- code = array_get(&system_names, ob.value.w, op);
- usn: if ( code < 0 )
- return code;
- if ( !r_has_type(op, t_name) )
- return_error(e_undefined);
- r_set_attrs(op, sattrs);
- break;
- default:
- goto str;
- }
- break;
- case bs_array:
- swap_size_also_value();
- atype = t_array;
- arr: if ( ob.value.w + ob.size.w > min_string_index ||
- ob.value.w & (sizeof_bin_seq_obj - 1)
- )
- return_error(e_syntaxerror);
- { uint aindex = ob.value.w / sizeof_bin_seq_obj;
- max_array_index =
- max(max_array_index, aindex + ob.size.w);
- make_tasv_new(op, atype,
- (ob.tx < 128 ? a_all :
- a_all + a_executable) | icurrent_space,
- ob.size.w, refs, abase + aindex);
- }
- break;
- case bs_dictionary: /* EXTENSION */
- swap_size_also_value();
- if ( (ob.size.w & 1) != 0 && ob.size.w != 1 )
- return_error(e_syntaxerror);
- atype = t_mixedarray; /* mark as dictionary */
- goto arr;
- case bs_mark:
- make_mark(op); break;
- default:
- return_error(e_syntaxerror);
- }
- }
- s_end_inline(s, p, rlimit);
- /* Shorten the objects to remove the space that turned out */
- /* to be used for strings. */
- iresize_ref_array(&pbs->bin_array, max_array_index,
- "binary object sequence(objects)");
- code = scan_bos_string_continue(s, pref, pstate);
- if ( code == scan_Refill )
- { pbs->cont = scan_bos_string_continue;
- }
- return code;
- }
-
- /* Reallocate the strings for a binary object sequence, */
- /* adjusting all the pointers to them from objects. */
- private byte *
- scan_bos_resize(scanner_state *pstate, uint new_size, uint index)
- { uint old_size = da_size(&pstate->s_da);
- byte *old_base = pstate->s_da.base;
- byte *new_base = iresize_string(old_base, old_size, new_size,
- "scan_bos_resize");
- byte *relocated_base = new_base + (new_size - old_size);
- uint i;
- ref *aptr = pbs->bin_array.value.refs;
- if ( new_base == 0 )
- return 0;
- /* Since the allocator normally extends strings downward, */
- /* it's quite possible that new and old addresses are the same. */
- if ( relocated_base != old_base )
- for ( i = index; i != 0; i--, aptr++ )
- if ( r_has_type(aptr, t_string) && r_size(aptr) != 0 )
- aptr->value.bytes =
- aptr->value.bytes - old_base + relocated_base;
- return new_base;
- }
-
- /* Continue reading the strings for a binary object sequence. */
- private int
- scan_bos_string_continue(register stream *s, ref *pref, scanner_state *pstate)
- { ref rstr;
- ref *op = pbs->bin_array.value.refs;
- int code = scan_bin_string_continue(s, &rstr, pstate);
- uint space = ialloc_space(idmemory);
- bool rescan = false;
- uint i;
-
- if ( code != 0 )
- return code;
- /* Finally, fix up names and dictionaries. */
- for ( i = r_size(&pbs->bin_array); i != 0; i--, op++ )
- switch ( r_type(op) )
- {
- case t_string:
- if ( r_has_attr(op, a_write) ) /* a real string */
- break;
- /* This is actually a name; look it up now. */
- { uint sattrs =
- (r_has_attr(op, a_executable) ? a_executable : 0);
- code = name_ref(op->value.bytes, r_size(op), op, 1);
- if ( code < 0 )
- return code;
- r_set_attrs(op, sattrs);
- }
- /* falls through */
- case t_name:
- if ( r_has_attr(op, a_read) ) /* bs_eval_name */
- { ref *defp = dict_find_name(op);
- if ( defp == 0 )
- return_error(e_undefined);
- store_check_space(space, defp);
- ref_assign(op, defp);
- }
- break;
- case t_mixedarray: /* actually a dictionary */
- { uint count = r_size(op);
- ref rdict;
- if ( count == 1 )
- { /* Indirect reference. */
- if ( op->value.refs < op )
- ref_assign(&rdict, op->value.refs);
- else
- { rescan = true;
- continue;
- }
- }
- else
- { code = dict_create(count >> 1, &rdict);
- if ( code < 0 )
- return code;
- while ( count )
- { count -= 2;
- code = dict_put(&rdict,
- &op->value.refs[count],
- &op->value.refs[count + 1]);
- if ( code < 0 )
- return code;
- }
- }
- r_set_attrs(&rdict, a_all);
- r_copy_attrs(&rdict, a_executable, op);
- ref_assign(op, &rdict);
- }
- break;
- }
- /* If there were any forward indirect references, */
- /* fix them up now. */
- if ( rescan )
- for ( op = pbs->bin_array.value.refs, i = r_size(&pbs->bin_array);
- i != 0; i--, op++
- )
- if ( r_has_type(op, t_mixedarray) )
- { const ref *piref = op->value.const_refs;
- ref rdict;
- if ( r_has_type(piref, t_mixedarray) ) /* ref to indirect */
- return_error(e_syntaxerror);
- ref_assign(&rdict, piref);
- r_copy_attrs(&rdict, a_executable, op);
- ref_assign(op, &rdict);
- }
- ref_assign(pref, &pbs->bin_array);
- r_set_size(pref, pbs->top_size);
- return scan_BOS;
- }
-